package cn.itcast.nems.common.captcha;

import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.symmetric.SymmetricAlgorithm;
import cn.hutool.crypto.symmetric.SymmetricCrypto;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.DecodedJWT;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.DigestUtils;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.ThreadLocalRandom;

@Slf4j
@Component
//@RefreshScope
@RequiredArgsConstructor
public class SmsCaptchaServiceImpl implements SmsCaptchaService {
	
	@Value("${JWT_SECRET_KEY:96b306f440252a160bca8cf2422405cb}")
	private String jwtSecretKey;
	
	// 验证码过期时间，单位：毫秒，默认：10分钟
	@Value("${EXPIRES:600000}")
	private Long expires;
	
	@Value("${DEBUG_MODE:false}")
	private Boolean isDebugMode;
	
	private final CaptchaService captchaService;
	
	@Override
	public boolean verify(String phone, String captcha, String token) {
	    if (Boolean.TRUE.equals(isDebugMode)) {
	        // 调试模式不做验证码的校验
	        return true;
        }
	    
	    byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.DES.getValue(), jwtSecretKey.getBytes()).getEncoded();
        SymmetricCrypto des = new SymmetricCrypto(SymmetricAlgorithm.DES, key);
        token = des.decryptStr(token);
	    
		DecodedJWT jwtDecoded = null;
		try {
			jwtDecoded = JWT.require(Algorithm.HMAC256(jwtSecretKey)).build().verify(token);
		} catch (JWTVerificationException e) {
			log.info("验证码TOKEN错误！" + e.getMessage());
			return false;
		}
		
		// 验证码是否正确
		String audience = jwtDecoded.getAudience().get(0);
		return audience.equalsIgnoreCase(this.generateAudience(phone, captcha, jwtDecoded.getExpiresAt()));
	}

	@Override
	public String send(final String mobile, final String captchaToken, final String captchaValue, final String tid) {
//		// 校验图形验证码   注：暂时不做校验！
//	    if(!captchaService.verify(captchaValue, captchaToken)) {
//	        throw new IllegalArgumentException("图形验证码不正确，请重新输入！");
//	    }
	    
	    // 生成验证码值
		String code = this.generateCode();
		
		// 发送短信
		SmsCaptchaSendUtil.sendCaptchaCode(mobile, code);
		
		// 生成验证码对应的token
		return this.generateToken(mobile, code);
	}

	/**
	 * 生成验证码token
	 * 
	 * @param answer 验证码答案
	 * @return
	 */
	private String generateToken(String phone, String code) {
		long currentTimeMillis = System.currentTimeMillis();
		Date currentAt = new Date(currentTimeMillis);
		Date expiresAt = new Date(currentTimeMillis + expires);
		String jwt = JWT.create().withAudience(generateAudience(phone, code, expiresAt)).withIssuedAt(currentAt).withExpiresAt(expiresAt).sign(Algorithm.HMAC256(jwtSecretKey));
		
        byte[] key = SecureUtil.generateKey(SymmetricAlgorithm.DES.getValue(), jwtSecretKey.getBytes()).getEncoded();
        SymmetricCrypto des = new SymmetricCrypto(SymmetricAlgorithm.DES, key);
		return des.encryptHex(jwt);
	}
	
	/**
	 * 生成验证码值
	 * @return
	 */
	private String generateCode() {
		return String.valueOf(ThreadLocalRandom.current().nextInt(100000, 1000000));
	}
	
	/**
	 * 生成jwt内的“听众”属性，用来最终判断值是否正确 <p/>
	 * 生成算法：MD5(expiresAt + jwtSecretKey + phone + code)
	 * 
	 * @param phone 手机号
	 * @param code 验证码值
	 * @return
	 */ 
	private String generateAudience(String phone, String code, Date expiresAt) {
		final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		return DigestUtils.md5DigestAsHex((sdf.format(expiresAt) + jwtSecretKey + phone + code).getBytes());
	}
}
